#include "tcpserver.h"
#include "ui_tcpserver.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>

TcpServer::TcpServer(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::TcpServer)
{
    ui->setupUi(this);

    tcpPort = 6666;
    tcpServer = new QTcpServer(this);

    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendMessage()));
}

TcpServer::~TcpServer()
{
    delete ui;
}

void TcpServer::initServer()
{
    payloadSize = 64*1024;
    TotalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;

    ui->serverStatusLabel->setText(tr("请选择需要发送的文件"));
    ui->progressBar->reset();
    ui->serverOpenBtn->setEnabled(true);
    ui->serverSendBtn->setEnabled(false);
    tcpServer->close();
}

void TcpServer::refused()
{
    // 文件被拒接接收
    tcpServer->close();
    ui->serverStatusLabel->setText("对方拒绝接收文件！！！");
}

void TcpServer::closeEvent(QCloseEvent *)
{
    // 窗口关闭
    on_serverColseBtn_clicked();
}

void TcpServer::sendMessage()
{
    ui->serverSendBtn->setEnabled(false);
    // 获取最新连接
    clientConnection = tcpServer->nextPendingConnection();
    // QIODevice, 每次将有效负载数据写入设备的当前写入通道时，都会发出此信号
    connect(clientConnection, SIGNAL(bytesWritten(qint64)), this, SLOT(updateClientProgress(qint64)));

    ui->serverStatusLabel->setText(tr("开始发送文件%1！").arg(theFileName));

    // 打开文件
    localFile = new QFile(fileName);
    if (!localFile->open(QFile::ReadOnly)) {
        QMessageBox::warning(this, "应用程序", tr("无法读取文件%1：\n%2").arg(fileName).arg(localFile->errorString()));
        return;
    }
    // 文件大小
    TotalBytes = localFile->size();
    // 输出流
    QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_6_7);
    // 开始计时
    elapsedTime.start();
    // 获取文件名
    QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf('/') - 1);

    sendOut << qint64(0); // 数据总大小，预分配头0-7字节
    sendOut << qint64(0); // 文件名大小，预分配8-15字节
    sendOut << currentFile;

    TotalBytes += outBlock.size();

    // 移动到开始位置
    sendOut.device()->seek(0);

    sendOut << TotalBytes; // 数据总大小
    sendOut << qint64((outBlock.size() - sizeof(qint64)*2)); // 文件名大小

    // 写出数据
    bytesToWrite = TotalBytes - clientConnection->write(outBlock);

    outBlock.resize(0);
}

void TcpServer::updateClientProgress(qint64 numBytes)
{
    // 防止界面卡顿，一边执行程序一边刷新界面
    qApp->processEvents();
    bytesWritten += (int)numBytes;
    if (bytesToWrite > 0) {
        // 取bytesToWrite, payloadSize中最小值读取文件部分数据
        outBlock = localFile->read(qMin(bytesToWrite, payloadSize));
        // 写入要发送的数据
        bytesToWrite -= (int)clientConnection->write(outBlock);
        // 清空读取的部分数据
        outBlock.resize(0);
    } else {
        localFile->close();
    }

    // 设置最大值与当前值
    ui->progressBar->setMaximum(TotalBytes);
    ui->progressBar->setValue(bytesWritten);

    // 计时结束
    qint64 useTime = elapsedTime.elapsed();
    // 计算发送的数据用时
    double speed = bytesWritten / useTime;
    ui->serverStatusLabel->setText(tr("已发送 %1MB (%2MB/s)\n共%3MB 已用时:%4秒\n估计剩余时间：%5秒")
                                       .arg(bytesWritten / (1024*1024))
                                       .arg(speed*1000 / (1024*1024), 0, 'f')
                                       .arg(TotalBytes / (1024 * 1024))
                                       .arg((useTime/1000, 0, 'f'))
                                       .arg(TotalBytes/speed/1000 - useTime/1000, 0, 'f'));

    if (bytesWritten == TotalBytes) {
        localFile->close();
        tcpServer->close();
        ui->serverStatusLabel->setText(tr("发送文件%1，成功").arg(theFileName));
    }
}

void TcpServer::on_serverOpenBtn_clicked()
{
    // 打开文件
    fileName = QFileDialog::getOpenFileName(this);
    if (!fileName.isEmpty()) {
        theFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/') - 1);
        ui->serverStatusLabel->setText(tr("要发送的文件为：").arg(theFileName));
        ui->serverSendBtn->setEnabled(true);
        ui->serverOpenBtn->setEnabled(false);
    }
}


void TcpServer::on_serverSendBtn_clicked()
{
    // 开启监听服务
    if (!tcpServer->listen(QHostAddress::Any, tcpPort)) {
        qDebug() << tcpServer->errorString();
        close();
        return;
    }
    ui->serverStatusLabel->setText("等待对方接收......");
    emit sendFileName(theFileName);
}


void TcpServer::on_serverColseBtn_clicked()
{
    // 关闭服务
    if (tcpServer->isListening()) {
        tcpServer->close();
        if (localFile->isOpen())
            localFile->close();
        clientConnection->abort();
    }
    close();
}

